/**
 * CaddiePieceOfProduct.java 21 juil. 07
 *
 * Copyright (c) 2007 windu.2b <jcaddie@windu2b.org>. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.windu2b.jcaddie.model;

import java.text.*;
import java.util.*;

/**
 * A piece of product in {@link Caddie caddie}.
 * @author windu.2b
 * 
 */
public class CaddiePieceOfProduct extends AbstractPieceOfProduct implements
        PieceOfProduct
{
	/**
	 * 
	 */
	private static final long	serialVersionUID	= 7292818724374434090L;


	private int	              quantite;


	private boolean	          visible, checked, editable;


	private String	          id;


	private Shop	          shop;


	private State	          state;


	private static State	  strikeName, unStrikeName;



	/**
	 * Properties on which caddie product may be sorted.
	 */
	public enum SortableProperty
	{
		CHECKED,

		QUANTITY,

		NAME,

		UNIT_PRICE,

		TOTAL_PRICE;
	}



	private static final Map<SortableProperty, Comparator<CaddiePieceOfProduct>>	SORTABLE_PROPERTY_COMPARATORS;

	/**
	 * Initialisation des comparateurs Ces comparateurs permettent de trier les
	 * colonnes d'un JTable selon différents critères.
	 */
	static
	{
		final Collator collator = Collator.getInstance();
		SORTABLE_PROPERTY_COMPARATORS = new HashMap<SortableProperty, Comparator<CaddiePieceOfProduct>>();

		SORTABLE_PROPERTY_COMPARATORS.put( SortableProperty.CHECKED,
		        new Comparator<CaddiePieceOfProduct>()
		        {
			        public int compare( CaddiePieceOfProduct piece1,
			                CaddiePieceOfProduct piece2 )
			        {
				        return CaddiePieceOfProduct.compare( piece1.checked,
				                piece2.checked );
			        }
		        } );

		SORTABLE_PROPERTY_COMPARATORS.put( SortableProperty.QUANTITY,
		        new Comparator<CaddiePieceOfProduct>()
		        {
			        public int compare( CaddiePieceOfProduct piece1,
			                CaddiePieceOfProduct piece2 )
			        {
				        return CaddiePieceOfProduct.compare( piece1.quantite,
				                piece2.quantite );
			        }
		        } );
		SORTABLE_PROPERTY_COMPARATORS.put( SortableProperty.NAME,
		        new Comparator<CaddiePieceOfProduct>()
		        {
			        public int compare( CaddiePieceOfProduct piece1,
			                CaddiePieceOfProduct piece2 )
			        {
				        return collator.compare( piece1.name, piece2.name );
			        }
		        } );

		SORTABLE_PROPERTY_COMPARATORS.put( SortableProperty.UNIT_PRICE,
		        new Comparator<CaddiePieceOfProduct>()
		        {
			        public int compare( CaddiePieceOfProduct piece1,
			                CaddiePieceOfProduct piece2 )
			        {
				        return CaddiePieceOfProduct.compare( piece1
				                .getUnitPrice(), piece2.getUnitPrice() );
			        }
		        } );

		SORTABLE_PROPERTY_COMPARATORS.put( SortableProperty.TOTAL_PRICE,
		        new Comparator<CaddiePieceOfProduct>()
		        {
			        public int compare( CaddiePieceOfProduct piece1,
			                CaddiePieceOfProduct piece2 )
			        {
				        return CaddiePieceOfProduct.compare( piece1
				                .getTotalPrice(), piece2.getTotalPrice() );
			        }
		        } );
	}




	/**
	 * Compare 2 valeurs de type <code>float</code>
	 * 
	 * @param value1
	 *            la première valeur
	 * @param value2
	 *            la deuxième valeur
	 * @return -1, 0 ou 1 selon que <code>value1</code> est respectivement
	 *         inférieur, égal ou supérieur à <code>value2</code>
	 */
	private static int compare( float value1, float value2 )
	{
		return value1 < value2 ? -1 : ( value1 == value2 ? 0 : 1 );
	}




	/**
	 * Compare 2 valeurs de type <code>boolean</code>
	 * 
	 * @param value1
	 * @param value2
	 * @return -1, 0 ou 1 selon que <code>value1</code> est respectivement
	 *         inférieur, égal ou supérieur à <code>value2</code>
	 */
	private static int compare( boolean value1, boolean value2 )
	{
		return value1 == value2 ? 0 : ( value1 ? -1 : 1 );
	}




	/**
	 * @param piece
	 */
	public CaddiePieceOfProduct( PieceOfProduct piece )
	{
		super( piece.getName(), piece.getIcon(), piece.getCategory(), piece
		        .getPrice(), piece.getPoids(), piece.getUnit() );
		if ( piece instanceof CaddiePieceOfProduct )
		{
			CaddiePieceOfProduct caddiePiece = ( CaddiePieceOfProduct ) piece;
			this.visible = caddiePiece.isVisible();
		}
		else
		{
			this.visible = true;
		}
		quantite = 1;

		strikeName = new StrikeName();
		unStrikeName = new UnStrikeName();
		state = unStrikeName;
	}




	/**
	 * @return La quantité déjà saisie pour ce produit
	 */
	public int getQuantite()
	{
		return quantite;
	}




	/**
	 * 
	 * @return Le prix total (ie le prix unitaire * la quantité) pour ce produit
	 */
	public float getTotalPrice()
	{
		return quantite * price;
	}




	/**
	 * @param quantite
	 *            the quantite to set
	 */
	public void setQuantite( int quantite )
	{
		this.quantite = quantite;
	}




	/**
	 * Returns a comparator that compares product on a given
	 * <code>property</code> in ascending order.
	 */
	public static Comparator<CaddiePieceOfProduct> getProductComparator(
	        SortableProperty property )
	{
		return SORTABLE_PROPERTY_COMPARATORS.get( property );
	}




	/**
	 * Returns <code>true</code> if this piece of product is visible.
	 */
	public boolean isVisible()
	{
		return this.visible;
	}




	/**
	 * Sets whether this piece of product is visible or not. This method
	 * should be called from {@link Caddie}, which controls notifications when a
	 * piece changed.
	 */
	void setVisible( boolean visible )
	{
		this.visible = visible;
	}




	/**
	 * Permet d'incrémenter de 1, la quantité du produit
	 */
	public void incremente()
	{
		addQuantite( 1 );
	}




	/**
	 * Permet de décrémenter de 1, la quantité du produit
	 */
	public void decremente()
	{
		removeQuantite( 1 );
	}




	/**
	 * Permet de rajouter <code>value</code> à la quantité du produit
	 * 
	 * @param value
	 *            la valeur à rajouter à la quantité du produit
	 */
	public void addQuantite( int value )
	{
		setQuantite( quantite + 1 );
	}




	/**
	 * Permet de supprimer <code>value</code> à la quantité du produit
	 * 
	 * @param value
	 *            la valeur à supprimer à la quantité du produit
	 */
	public void removeQuantite( int value )
	{
		quantite -= value;
		if ( quantite < 0 ) quantite = 0;
	}




	/**
	 * @return si le produit a été coché ou non
	 */
	public boolean isChecked()
	{
		return checked;
	}




	/**
	 * @param checked
	 *            the checked to set
	 */
	public void setChecked( boolean checked )
	{
		this.checked = checked;
	}




	/**
	 * @return the editable
	 */
	public boolean isEditable()
	{
		return editable;
	}




	/**
	 * @param editable
	 *            the editable to set
	 */
	public void setEditable( boolean editable )
	{
		this.editable = editable;
	}




	/**
	 * @return the id
	 */
	public String getId()
	{
		return id;
	}




	/**
	 * @param id
	 *            the id to set
	 */
	public void setId( String id )
	{
		this.id = id;
	}




	/**
	 * @return the shop
	 */
	public Shop getShop()
	{
		return shop;
	}




	/**
	 * @param shop
	 *            the shop to set
	 */
	public void setShop( Shop shop )
	{
		this.shop = shop;
	}




	/**
	 * @return the shop
	 */
	public Enseigne getEnseigne()
	{
		return shop.getEnseigne();
	}




	/**
	 * @param enseigne Le nom de l'enseigne dans laquelle se produit est pris
	 */
	public void setEnseigne( Enseigne enseigne )
	{
		this.shop.setEnseigne( enseigne );
	}




	/**
	 * 
	 * @see org.windu2b.jcaddie.model.AbstractPieceOfProduct#getName()
	 */
	public String getName()
	{
		return state.toString();
	}




	/**
	 * 
	 * @param type Permet de préciser le mode d'affichage du nom du produit
	 * STRIKE = affichage normal
	 * UNSTRIKE = affichage barré
	 */
	public void setState( State.TYPE type )
	{
		switch ( type )
		{
			case STRIKE :
				state = strikeName;
				break;

			case UNSTRIKE :
				state = unStrikeName;
				break;
		}
	}



	private class StrikeName implements State
	{
		public String toString()
		{
			return "<html><strike>" + name + "</strike></html>";
		}
	}

	private class UnStrikeName implements State
	{
		public String toString()
		{
			return name;
		}
	}
}